; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=gvn < %s | FileCheck %s


define i64 @test1(i1 %c, i64 %a, i64 %b) {
; CHECK-LABEL: @test1(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ [[A:%.*]], [[TAKEN]] ], [ [[B:%.*]], [[UNTAKEN]] ]
; CHECK-NEXT:    ret i64 0
;
  br i1 %c, label %taken, label %untaken
taken:
  br label %merge
untaken:
  br label %merge
merge:
  %phi1 = phi i64 [%a, %taken], [%b, %untaken]
  %phi2 = phi i64 [%a, %taken], [%b, %untaken]
  %ret = sub i64 %phi1, %phi2
  ret i64 %ret
}

declare void @llvm.assume(i1)

define i64 @test2(i1 %c, i64 %a, i64 %b) {
; CHECK-LABEL: @test2(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    [[ASSUMPTION:%.*]] = icmp eq i64 [[A:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[ASSUMPTION]])
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ 0, [[TAKEN]] ], [ [[B:%.*]], [[UNTAKEN]] ]
; CHECK-NEXT:    ret i64 0
;
  br i1 %c, label %taken, label %untaken
taken:
  %assumption = icmp eq i64 %a, 0
  call void @llvm.assume(i1 %assumption)
  br label %merge
untaken:
  br label %merge
merge:
  %phi1 = phi i64 [%a, %taken], [%b, %untaken]
  %phi2 = phi i64 [0, %taken], [%b, %untaken]
  %ret = sub i64 %phi1, %phi2
  ret i64 %ret
}


define i64 @test3(i1 %c, i64 %a, i64 %b) {
; CHECK-LABEL: @test3(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    [[ADD1:%.*]] = add i64 [[A:%.*]], 5
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ [[ADD1]], [[TAKEN]] ], [ [[B:%.*]], [[UNTAKEN]] ]
; CHECK-NEXT:    ret i64 0
;
  br i1 %c, label %taken, label %untaken
taken:
  %add1 = add i64 %a, 5
  %add2 = add i64 %a, 5
  br label %merge
untaken:
  br label %merge
merge:
  %phi1 = phi i64 [%add1, %taken], [%b, %untaken]
  %phi2 = phi i64 [%add2, %taken], [%b, %untaken]
  %ret = sub i64 %phi1, %phi2
  ret i64 %ret
}

define i64 @test4(i1 %c, i64 %a, i64 %b) {
; CHECK-LABEL: @test4(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    [[PHI1:%.*]] = phi i64 [ [[A:%.*]], [[TAKEN]] ], [ [[B:%.*]], [[UNTAKEN]] ]
; CHECK-NEXT:    br i1 [[C]], label [[TAKEN2:%.*]], label [[UNTAKEN2:%.*]]
; CHECK:       taken2:
; CHECK-NEXT:    [[ADD1:%.*]] = add i64 [[PHI1]], 5
; CHECK-NEXT:    br label [[MERGE2:%.*]]
; CHECK:       untaken2:
; CHECK-NEXT:    br label [[MERGE2]]
; CHECK:       merge2:
; CHECK-NEXT:    [[PHI3:%.*]] = phi i64 [ [[ADD1]], [[TAKEN2]] ], [ [[PHI1]], [[UNTAKEN2]] ]
; CHECK-NEXT:    ret i64 0
;
  br i1 %c, label %taken, label %untaken
taken:
  br label %merge
untaken:
  br label %merge
merge:
  %phi1 = phi i64 [%a, %taken], [%b, %untaken]
  %phi2 = phi i64 [%a, %taken], [%b, %untaken]
  br i1 %c, label %taken2, label %untaken2
taken2:
  %add1 = add i64 %phi1, 5
  %add2 = add i64 %phi2, 5
  br label %merge2
untaken2:
  br label %merge2
merge2:
  %phi3 = phi i64 [%add1, %taken2], [%phi2, %untaken2]
  %phi4 = phi i64 [%add2, %taken2], [%phi2, %untaken2]
  %ret = sub i64 %phi4, %phi3
  ret i64 %ret
}

define i64 @test5(i1 %c, i64 %a) {
; CHECK-LABEL: @test5(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    [[ASSUMPTION:%.*]] = icmp eq i64 [[A:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[ASSUMPTION]])
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    ret i64 0
;
  br i1 %c, label %taken, label %untaken
taken:
  %assumption = icmp eq i64 %a, 0
  call void @llvm.assume(i1 %assumption)
  br label %merge
untaken:
  br label %merge
merge:
  %phi = phi i64 [%a, %taken], [0, %untaken]
  ret i64 %phi
}

define i64 @test6(i1 %c, i64 %a) {
; CHECK-LABEL: @test6(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    [[ASSUMPTION:%.*]] = icmp eq i64 [[A:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[ASSUMPTION]])
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    ret i64 0
;
  br i1 %c, label %taken, label %untaken
taken:
  %assumption = icmp eq i64 %a, 0
  call void @llvm.assume(i1 %assumption)
  br label %next
next:
  br label %merge
untaken:
  br label %merge
merge:
  %phi = phi i64 [%a, %next], [0, %untaken]
  ret i64 %phi
}

; negative test, phi use is NOT dominated by assume
define i64 @test7(i1 %c, i64 %a) {
; CHECK-LABEL: @test7(
; CHECK-NEXT:    br i1 [[C:%.*]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
; CHECK:       taken:
; CHECK-NEXT:    [[ASSUMPTION:%.*]] = icmp eq i64 [[A:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[ASSUMPTION]])
; CHECK-NEXT:    br label [[MERGE:%.*]]
; CHECK:       untaken:
; CHECK-NEXT:    br label [[MERGE]]
; CHECK:       merge:
; CHECK-NEXT:    ret i64 [[A]]
;
  br i1 %c, label %taken, label %untaken
taken:
  %assumption = icmp eq i64 %a, 0
  call void @llvm.assume(i1 %assumption)
  br label %merge
untaken:
  br label %merge
merge:
  br label %next
next:
  %phi = phi i64 [%a, %merge]
  ret i64 %phi
}
